package cn.ac.zing.server.hj212.runner;

import cn.ac.zing.server.hj212.node.NodeContainer;
import cn.ac.zing.server.hj212.processor.ProcessorImpl;
import cn.ac.zing.server.hj212.processor.bean.ProcessorBean;
import cn.ac.zing.server.hj212.stater.AbstractStarter;
import cn.ac.zing.server.util.FileUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.LinkedList;

/**
 * 加载配置文件入口
 *
 * @Author：dcy
 * @name：LoadConfigRunner
 * @Date：2024/5/19 10:25
 */
@Component
@Slf4j
public class LoadConfigRunner implements CommandLineRunner {


    LinkedList<JSONObject> taskConfig = new LinkedList<>();

    /**
     * 节点任务
     */
    LinkedList<NodeContainer> tasks = new LinkedList<>();

    @Override
    public void run(String... args) throws Exception {
        String hj212CollectorFile = "config/hj212.json";
        InputStream in = this.getClass().getClassLoader().getResourceAsStream(hj212CollectorFile);
        String configString = FileUtil.getFileContent(in);
        JSONObject config = JSON.parseObject(configString);
        log.info("加载配置文件: {} ", config.toJSONString());

        try {
            getNext(config.getString("start"), config);

            ProcessorBean bean = new ProcessorBean();
            ProcessorImpl step = null;

            Class<?> z = null;
            for (JSONObject obj : taskConfig) {
                if (obj.containsKey("start")) {
                    continue;
                }
                bean = new ProcessorBean();
                bean.setAsync(obj.getBooleanValue("async"));

                bean.setName(obj.getString("name"));


                if (StringUtils.isNotBlank(obj.getString("preProcessor"))) {
                    z = Class.forName(obj.getString("preProcessor"));
                    step = (ProcessorImpl) z.getConstructor(JSONObject.class).newInstance(obj);
                    bean.setPreProcessor(step);
                }

                if (StringUtils.isNotBlank(obj.getString("processor"))) {
                    z = Class.forName(obj.getString("processor"));
                    // 将当前配置传到构造器中
                    step = (ProcessorImpl) z.getConstructor(JSONObject.class).newInstance(obj);
                    bean.setProcessor(step);
                }

                // 没有后置处理器
                if (StringUtils.isNotBlank(obj.getString("postProcessor"))) {
                    z = Class.forName(obj.getString("postProcessor"));
                    step = (ProcessorImpl) z.getConstructor(JSONObject.class).newInstance(obj);
                    bean.setPostProcessor(step);
                }
                // 节点任务保存
                tasks.add(new NodeContainer(bean));
            }

            JSONObject startConfig = config.getJSONObject("task").getJSONObject(config.getString("start"));

            String startClassName = startConfig.getString("start");

            Class<?> startClazz = Class.forName(startClassName);
            Constructor<?> c = startClazz.getConstructor(JSONObject.class);

            AbstractStarter start = (AbstractStarter) c.newInstance(config);
            Field field = start.getClass().getField("nodes");
            field.setAccessible(true);
            // 将链式的任务节点set进去
            field.set(start, tasks);
            // 启动netty
            start.execute(startConfig.getJSONObject("params"));
        } catch (Exception e) {
            log.error("任务节点初始化失败 任务名称：" + config.getString("name"), e);
            e.printStackTrace();
            System.exit(0);
        }
    }

    private void getNext(String parent, JSONObject config) {
        JSONObject task = config.getJSONObject("task");
        JSONArray next = new JSONArray();
        JSONObject node = new JSONObject();
        for (String key : task.keySet()) {
            if (key.equals(parent)) {
                node = task.getJSONObject(key);
                node.put("name", key);
                taskConfig.add(node);
                next = task.getJSONObject(key).getJSONArray("next");
                if (next != null && next.size() > 0) {
                    for (Object object : next) {
                        getNext(String.valueOf(object), config);
                    }
                }
            }
        }
    }
}
